﻿#include "geometry.h"

char HitBoundingBox(double minB[NUMDIM], double maxB[NUMDIM], double origin[NUMDIM], double dir[NUMDIM], double coord[NUMDIM]) {
	char inside = TRUE;
	char quadrant[NUMDIM];
	register int i;
	int whichPlane;
	double maxT[NUMDIM];
	double candidatePlane[NUMDIM];

	/* Find candidate planes; this loop can be avoided if
	rays cast all from the eye(assume perpsective view) */
	for (i = 0; i < NUMDIM; i++)
		if (origin[i] < minB[i]) {
			quadrant[i] = LEFT;
			candidatePlane[i] = minB[i];
			inside = FALSE;
		}
		else if (origin[i] > maxB[i]) {
			quadrant[i] = RIGHT;
			candidatePlane[i] = maxB[i];
			inside = FALSE;
		}
		else {
			quadrant[i] = MIDDLE;
		}

	/* Ray origin inside bounding box */
	if (inside) {
		coord = origin;
		return (TRUE);
	}


	/* Calculate T distances to candidate planes */
	for (i = 0; i < NUMDIM; i++)
		if (quadrant[i] != MIDDLE && dir[i] != 0.)
			maxT[i] = (candidatePlane[i] - origin[i]) / dir[i];
		else
			maxT[i] = -1.;

	/* Get largest of the maxT's for final choice of intersection */
	whichPlane = 0;
	for (i = 1; i < NUMDIM; i++)
		if (maxT[whichPlane] < maxT[i])
			whichPlane = i;

	/* Check final candidate actually inside box */
	if (maxT[whichPlane] < 0.) return (FALSE);
	for (i = 0; i < NUMDIM; i++)
		if (whichPlane != i) {
			coord[i] = origin[i] + maxT[whichPlane] * dir[i];
			if (coord[i] < minB[i] || coord[i] > maxB[i])
				return (FALSE);
		}
		else {
			coord[i] = candidatePlane[i];
		}
	return (TRUE);				/* ray hits box */
}

//bool HitBoundingBox(const Vec3f& minB, const Vec3f& maxB, const Vec3f& origin, const Vec3f& dir, Vec3f& coord) {
//	double _minB[3] = { minB.x, minB.y, minB.z };
//	double _maxB[3] = { maxB.x, maxB.y, maxB.z };
//	double _origin[3] = { origin.x, origin.y, origin.z };
//	double _dir[3] = { dir.x, dir.y, dir.z };
//	double _coord[3];
//	if (HitBoundingBox(_minB, _maxB, _origin, _dir, _coord)) {
//		coord = Vec3f(_coord[0], _coord[1], _coord[2]);
//		return true;
//	}
//	return false;
//}

// https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection
// https://tavianator.com/2011/ray_box.html
bool HitBoundingBoxP(const Vec3f& minB, const Vec3f& maxB, const Vec3f& origin, const Vec3f& dir) {
	Vec3f dirfrac;
	// r.dir is unit direction vector of ray
	dirfrac.x = 1.0f / dir.x;
	dirfrac.y = 1.0f / dir.y;
	dirfrac.z = 1.0f / dir.z;
	// lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
	// r.org is origin of ray
	float t1 = (minB.x - origin.x) * dirfrac.x;
	float t2 = (maxB.x - origin.x) * dirfrac.x;
	float t3 = (minB.y - origin.y) * dirfrac.y;
	float t4 = (maxB.y - origin.y) * dirfrac.y;
	float t5 = (minB.z - origin.z) * dirfrac.z;
	float t6 = (maxB.z - origin.z) * dirfrac.z;

	float tmin = std::max(std::max(std::min(t1, t2), std::min(t3, t4)), std::min(t5, t6));
	float tmax = std::min(std::min(std::max(t1, t2), std::max(t3, t4)), std::max(t5, t6));

	// if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
	if (tmax < 0) {
		return false;
	}

	// if tmin > tmax, ray doesn't intersect AABB
	if (tmin > tmax) {
		return false;
	}

	return true;
}
